package br.com.wai2008.client.protocol;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import br.com.wai2008.client.dataobject.WAILocalizationObject;
import br.com.wai2008.client.dataobject.WAIServiceObject;
import br.com.wai2008.socket.protocol.ClientToServerProtocol;

/**
 * This class applies the Client to Server protocol necessary
 * to request the WAI service. It also parse the message received
 * from an execution of system commands, as getting HD Number Serial
 * and getting wireless signals.
 * 
 * @since 
 * 		September, 2008.
 * 
 * @version
 * 		WAI2008 - version 1.0
 * 
 * @author 
 * 		Andre Romero Goncales
 */
public class ApplyProtocol {

	/**
	 * Build the message necessary to request the WAI Service on Server. This message
	 * must be in a specific protocol.
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * 
	 * @param
	 * 		userHDNumber return of a system command execution that gets the
	 * 		HD serial number. This system command is 'hdparm'.
	 * @param
	 * 		wirelessSignal return of a system command execution that gets the
	 * 		wireless signals. This system command is 'iwlist'.
	 * @param
	 * 		target The user's target.
	 * @param
	 * 		floor The user's floor.
	 * @param
	 * 		restriction The user's restriction.
	 * 		<VERIFICAR AS RESTRICOES>
	 * @param
	 * 		language The user's language.
	 * 		<VERIFICAR AS RESTRICOES>
	 * 
	 * @return
	 * 		The message built in a specific protocol that is necessary to request
	 * 		the service on server or <b>null</b> if hd serial number or wireless signals
	 * 		couldn't be found.
	 */
	public static String buildMessage(BufferedReader userHDNumber, BufferedReader wirelessSignal, String target,
			int floor, int restriction, String language) {
		String[] signalMessages = buildWirelessSignalMessage(wirelessSignal);
		String hdNumber = buildHDNumberMessage(userHDNumber);
		if (hdNumber != null && signalMessages != null) {
			StringBuilder sb = new StringBuilder();
			sb.append(ClientToServerProtocol.TAG_CS_ROOT_START);
			sb.append(ClientToServerProtocol.TAG_CS_SIMULATION_START);
			sb.append(false);
			sb.append(ClientToServerProtocol.TAG_CS_SIMULATION_END);
			sb.append(ClientToServerProtocol.TAG_CS_HDSERIAL_START);
			sb.append(hdNumber);
			sb.append(ClientToServerProtocol.TAG_CS_HDSERIAL_END);
			for (int i=0; i < signalMessages.length; i++) {
				sb.append(ClientToServerProtocol.TAG_CS_NETWORK_START);
				sb.append(ClientToServerProtocol.TAG_CS_ID_START);
				sb.append(signalMessages[i]);
				sb.append(ClientToServerProtocol.TAG_CS_ID_END);
				sb.append(ClientToServerProtocol.TAG_CS_SIGNAL_START);
				sb.append(signalMessages[++i]);
				sb.append(ClientToServerProtocol.TAG_CS_SIGNAL_END);
				sb.append(ClientToServerProtocol.TAG_CS_NETWORK_END);
			}
			sb.append(ClientToServerProtocol.TAG_CS_TARGET_START);
			sb.append(target);
			sb.append(ClientToServerProtocol.TAG_CS_TARGET_END);
			sb.append(ClientToServerProtocol.TAG_CS_FLOOR_START);
			sb.append(floor);
			sb.append(ClientToServerProtocol.TAG_CS_FLOOR_END);
			sb.append(ClientToServerProtocol.TAG_CS_RESTRICTION_START);
			sb.append(restriction);
			sb.append(ClientToServerProtocol.TAG_CS_RESTRICTION_END);
			sb.append(ClientToServerProtocol.TAG_CS_LANGUAGE_START);
			sb.append(language);
			sb.append(ClientToServerProtocol.TAG_CS_LANGUAGE_END);
			sb.append(ClientToServerProtocol.TAG_CS_ROOT_END);
			sb.append(ClientToServerProtocol.END_LINE);
			return sb.toString();
		} else {
			return null;	
		}
	}
	
	public static String buildSimulationMessage(BufferedReader userHDNumber, WAILocalizationObject object, String target,
			int restriction, String language) {
		String hdNumber = buildHDNumberMessage(userHDNumber);
		if (hdNumber != null && object != null) {
			StringBuilder sb = new StringBuilder();
			sb.append(ClientToServerProtocol.TAG_CS_ROOT_START);
			sb.append(ClientToServerProtocol.TAG_CS_SIMULATION_START);
			sb.append(true);
			sb.append(ClientToServerProtocol.TAG_CS_SIMULATION_END);
			sb.append(ClientToServerProtocol.TAG_CS_HDSERIAL_START);
			sb.append(hdNumber);
			sb.append(ClientToServerProtocol.TAG_CS_HDSERIAL_END);			
			sb.append(ClientToServerProtocol.TAG_CS_INITIALLOCALIZATION_START);
			sb.append(ClientToServerProtocol.TAG_CS_X_START);
			sb.append(object.getX());
			sb.append(ClientToServerProtocol.TAG_CS_X_END);
			sb.append(ClientToServerProtocol.TAG_CS_Y_START);
			sb.append(object.getY());
			sb.append(ClientToServerProtocol.TAG_CS_Y_END);
			sb.append(ClientToServerProtocol.TAG_CS_FLOOR_START);
			sb.append(object.getAndar());
			sb.append(ClientToServerProtocol.TAG_CS_FLOOR_END);
			sb.append(ClientToServerProtocol.TAG_CS_INITIALLOCALIZATION_END);			
			sb.append(ClientToServerProtocol.TAG_CS_TARGET_START);
			sb.append(target);
			sb.append(ClientToServerProtocol.TAG_CS_TARGET_END);
			sb.append(ClientToServerProtocol.TAG_CS_RESTRICTION_START);
			sb.append(restriction);
			sb.append(ClientToServerProtocol.TAG_CS_RESTRICTION_END);
			sb.append(ClientToServerProtocol.TAG_CS_LANGUAGE_START);
			sb.append(language);
			sb.append(ClientToServerProtocol.TAG_CS_LANGUAGE_END);
			sb.append(ClientToServerProtocol.TAG_CS_ROOT_END);
			sb.append(ClientToServerProtocol.END_LINE);
			return sb.toString();
		} else {
			return null;	
		}
	}
	
	public static WAIServiceObject buildDataObject(String message) {
		System.out.println("[ApplyProtocol] Getting Data Object from Server Message...");
		if (message != null) {
			WAIServiceObject serviceDataObject = new WAIServiceObject();
			if(message.contains(ClientToServerProtocol.TAG_SC_CODE_START)) {
				System.out.println("[ApplyProtocol] ERROR RETURNED FROM SERVER...");
				
				String errorCode = message.substring(message.indexOf(
						ClientToServerProtocol.TAG_SC_CODE_START) + 
						ClientToServerProtocol.TAG_SC_CODE_START.length(), 
						message.indexOf(ClientToServerProtocol.TAG_SC_CODE_END)
						);

				String errorDescription = message.substring(message.indexOf(
						ClientToServerProtocol.TAG_SC_DESCRIPTION_START) + 
						ClientToServerProtocol.TAG_SC_DESCRIPTION_START.length(), 
						message.indexOf(ClientToServerProtocol.TAG_SC_DESCRIPTION_END)
						);
				
				serviceDataObject.setErrorCode(errorCode);
				serviceDataObject.setErrorDescription(errorDescription);
				
			} else {
				System.out.println("[ApplyProtocol] SUCCESS RETURNED FROM SERVER...");

				List<WAILocalizationObject> route = new ArrayList<WAILocalizationObject>();				
				while (message.contains(ClientToServerProtocol.TAG_SC_LOCALIZATION_START)) {
					message = message.substring(message.indexOf(
							ClientToServerProtocol.TAG_SC_LOCALIZATION_START) + 
							ClientToServerProtocol.TAG_SC_LOCALIZATION_START.length());

					int x = Integer.parseInt(message.substring(message.indexOf(
											ClientToServerProtocol.TAG_SC_X_START) + 
											ClientToServerProtocol.TAG_SC_X_START.length(), 
											message.indexOf(ClientToServerProtocol.TAG_SC_X_END)
											));
					
					int y = Integer.parseInt(message.substring(message.indexOf(
							ClientToServerProtocol.TAG_SC_Y_START) + 
							ClientToServerProtocol.TAG_SC_Y_START.length(), 
							message.indexOf(ClientToServerProtocol.TAG_SC_Y_END)
							));
					
					int floor = Integer.parseInt(message.substring(message.indexOf(
											ClientToServerProtocol.TAG_SC_FLOOR_START) + 
											ClientToServerProtocol.TAG_SC_FLOOR_START.length(), 
											message.indexOf(ClientToServerProtocol.TAG_SC_FLOOR_END)
											));					

					message = message.substring(message.indexOf(
							ClientToServerProtocol.TAG_SC_LOCALIZATION_END) + 
							ClientToServerProtocol.TAG_SC_LOCALIZATION_END.length());
					
					WAILocalizationObject localization = new WAILocalizationObject(x, y, floor);
					route.add(localization);
				}

				if (message.contains(ClientToServerProtocol.TAG_SC_MESSAGE_START)) {
					String messageToSpeech = message.substring(message.indexOf(
							ClientToServerProtocol.TAG_SC_MESSAGE_START) + 
							ClientToServerProtocol.TAG_SC_MESSAGE_START.length(), 
							message.indexOf(ClientToServerProtocol.TAG_SC_MESSAGE_END)
							);

					serviceDataObject.setMessage(messageToSpeech);	
				}				
				serviceDataObject.setRoute(route.toArray(new WAILocalizationObject[route.size()]));			
			}
			return serviceDataObject;
		} else {
			System.out.println("[ApplyProtocol] ERROR: An Error occur while trying to" +
					" get the route from message returned from Server: output message null");
			return null;
		}
	}

	/**
	 * Parse the message received from the system command execution that gets the
	 * HD serial number.
	 * 
	 * @see
	 * 		br.com.wai2008.client.serial.HDSerialNumber
	 * 
	 * @param
	 * 		userHDNumber return of a system command execution that gets the
	 * 		HD serial number. This system command is 'hdparm'.
	 * 
	 * @return
	 * 		The HD serial Number or <b>null</b> if cannot be found.
	 */
	private static String buildHDNumberMessage(BufferedReader userHDNumber) {
		String hdNumber = null;
		if (userHDNumber != null) {
			String line = null;
			try {
				while ((line = userHDNumber.readLine()) != null) {
					if (line.contains("SerialNo=           ")) {
						hdNumber = line.substring(line.indexOf("SerialNo=           ") + 20, line.length());
					}					
				}
				if (hdNumber == null) {
					System.out.println("[ApplyProtocol] ERROR: HD Serial Number not found");
				}
			} catch (IOException e) {
				System.out.println("[ApplyProtocol] ERROR: Cannot read system command return for HD Serial Number");
				e.printStackTrace();
			}
		}
		System.out.println("DEBUG: " + hdNumber);
		return hdNumber;
	}

	/**
	 * Parse the message received from the system command execution that gets the
	 * wireless signals.
	 * 
	 * @see
	 * 		br.com.wai2008.client.wireless.WirelessSignal
	 * 
	 * @param
	 * 		wirelessSignal return of a system command execution that gets the
	 * 		wireless signals. This system command is 'iwlist'.
	 * 
	 * @return
	 * 		The wireless signals or <b>null</b> if cannot be found.
	 * 		Each wireless signal contain an ID and a signal power, as in the
	 * 		following example:
	 * 		String[0] = ID, String[1] = signal, String[2] = ID, ...
	 */
	public static String[] buildWirelessSignalMessage(BufferedReader wirelessSignal) {
		if (wirelessSignal != null) {
			List<String> message = new ArrayList<String>();
			String line = null;
			try {
				boolean hasValue = false;
				while ((line = wirelessSignal.readLine()) != null) {
					hasValue = true;
					if (line.length() <= 0) {
						throw new IOException();
					}
					int firstIndex = line.indexOf("\u0009");
					int lastIndex = line.lastIndexOf("\u0009");
					if (firstIndex > -1 && lastIndex > -1) {
						String networkID = line.substring(0, firstIndex);
						String networkSignal = line.substring(lastIndex + 1, line.length());
						if (new Integer(networkSignal) > -80) {
							message.add(networkID);
							message.add(networkSignal);
						}
					}
				}
				
				if (hasValue) {
					return message.toArray(new String[message.size()]);
				} else {
					System.out.println("[ApplyProtocol] ERROR: Wireless Signal not found");
				}
			} catch (IOException e) {
				System.out.println("[ApplyProtocol] ERROR: Cannot read system command return for wireless signal");
				e.printStackTrace();
			}
		}
		return null;
	}
}
